﻿/// <reference path="framework.js" />
RexToy.registerNamespace("RexToy.UnitTest");

RexToy.UnitTest = {
    fixtureCount: 0,
    testCaseCount: 0,
    failCount: 0,
    successCount: 0,
    assertCount: 0,
    fixtures: [],
    fixtureNames: [],
    failCase: [],
    callBack: null,
    registerFixture: function (fixtureName) {
        /// <summary>All test fixture should be registered by this method</summary>
        try {
            var fixture = RexToy.Activator.createInstance(fixtureName);
            this.fixtureNames.push(fixtureName);
            this.fixtures.push(fixture);
            this.fixtureCount++;
            for (var m in fixture) {
                if (m.startWith('test'))
                    this.testCaseCount++;
            }
        } catch (e) {
            console.error('Create instance of [' + fixtureName + '] failed. Test fixture skipped. -> ' + e);
        }
    },

    run: function (callBack) {
        this.successCount = 0;
        this.failCount = 0;
        this.assertCount = 0;
        this.callBack = callBack;

        console.log("================Test start================");

        for (var i = 0; i < this.fixtures.length; i++) {
            //console.log(String.format("=====Test Fixture [{0}]=====", this.fixtureNames[i]));
            this.runFixture(this.fixtures[i], this.fixtureNames[i]);
        }

        console.log("================Test end================");
        console.log(String.format("Result => Fixture:{0}, TestCase:{1}, Fail:{2}, Success:{3}, Assert:{4}, {5}% Passed.", this.fixtureCount, this.testCaseCount, this.failCount, this.successCount, this.assertCount, this.successCount/this.testCaseCount*100));
    },

    runFixture: function (fixture, fixtureName) {
        var setUp, tearDown, fixtureSetUp, fixtureTearDown;

        for (var m in fixture) {
            if (m == "setUp") {
                setUp = m;
                continue;
            }

            if (m == "tearDown") {
                tearDown = m;
                continue;
            }

            if (m == "fixtureSetUp") {
                fixtureSetUp = m;
                continue;
            }

            if (m == "fixtureTearDown") {
                fixtureTearDown = m;
                continue;
            }
        }

        if (fixtureSetUp) {
            try {
                fixture[fixtureSetUp]();
            } catch (e) {
                console.error("Fixture[" + fixtureName + "] SetUp error -> " + e);
            }
        }

        for (var test in fixture) {
            if (test.startWith("test")) {
                var msg, success;
                if (setUp) {
                    try {
                        fixture[setUp]();
                    } catch (e) {
                        console.error("Case[" + test + "] SetUp error -> " + e);
                    }
                }

                try {
                    fixture[test]();
                    msg = String.format("[{0}].[{1}] success.", fixtureName, test);
                    console.log(msg);
                    success = true;
                    this.successCount++;
                }
                catch (e) {
                    msg = String.format("[{0}].[{1}] failed. --> {2}", fixtureName, test, e);
                    console.error(msg);
                    success = false;
                    this.failCount++;
                }

                if (tearDown) {
                    try {
                        fixture[tearDown]();
                    } catch (e) {
                        console.error("Case[" + test + "] TearDown error -> " + e);
                    }
                }

                if (this.callBack) {
                    try {
                        this.callBack(fixtureName, test, msg, success, this.successCount + this.failCount);
                    } catch (e) {
                        console.error("Error occur in callback passed to UnitTest framework -> " + e);
                    }
                }
            }
        }

        if (fixtureTearDown) {
            try {
                fixture[fixtureTearDown]();
            } catch (e) {
                console.error("Fixture[" + fixtureName + "] TearDown error -> " + e);
            }
        }
    }
};

RexToy.UnitTest.Assert = {
    isTrue: function (expression, msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        if (expression !== true) {
            var detail = String.format("[{0} !== true]", expression);
            throw detail + msg;
        }
    },

    isFalse: function (expression, msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        if (expression !== false) {
            var detail = String.format("[{0} !== false]", expression);
            throw detail + msg;
        }
    },

    areEqual: function (x, y, msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        if (x !== y) {
            var detail = String.format("[{0} !== {1}]", x, y);
            throw detail + msg;
        }
    },

    isNotNull: function (obj, msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        if (obj == null) {
            var detail = String.format("[{0} == null]", obj);
            throw detail + msg;
        }
    },

    isNull: function (obj, msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        if (obj !== null) {
            var detail = String.format("[{0} !== null]", obj);
            throw detail + msg;
        }
    },

    fail: function (msg) {
        if (!msg) msg = String.Empty;
        RexToy.UnitTest.assertCount++;
        throw 'Fail' + msg;
    }
};

var $assert = RexToy.UnitTest.Assert;